﻿#pragma once

#include <xy/topo/shape.h>

namespace xy
{

namespace topo
{

template <std::size_t N> struct mesh_t
{
    std::unordered_set<vertex_t *> vertices{};
    std::unordered_set<edge_t *> edges{};
    std::unordered_set<coedge_t *> coedges{};
    std::unordered_set<face_t *> faces{};

    /**
     * @brief 默认构造
     *
     */
    mesh_t() = default;

    /**
     * @brief 删除所有赋值和拷贝构造函数
     *
     */
    mesh_t(mesh_t &&) = delete;

    /**
     * @brief 析构
     *
     */
    virtual ~mesh_t()
    {
        for (auto v : vertices)
            shape_t::remove(v);
    }

    /**
     * @brief 判断是否为空
     *
     * @return true
     * @return false
     */
    bool empty() const
    {
        return vertices.empty();
    }

    /**
     * @brief 创建顶点，并返回指针（不再考虑顶点在几何上是否重合）
     *
     * @return VertexHandle
     */
    vertex_t *create_vertex()
    {
        auto v = vertex_t::create();
        vertices.insert(v);
        return v;
    }

    /**
     * @brief 创建边，返回与输入顶点顺序同向的 coedge_t
     *
     * @param[in] v1
     * @param[in] v2
     * @return coedge_t *
     */
    coedge_t *create_edge(vertex_t *v1, vertex_t *v2)
    {
        auto e = edge_t::create(v1, v2);
        edges.insert(e);

        coedges.insert(e->coedge);
        coedges.insert(e->coedge->twin);

        return e->coedge;
    }

    /**
     * @brief 多个 coedge_t 创建面
     *
     * @tparam Args
     */
    template <typename... Args>
        requires((N == 0 || sizeof...(Args) == N) && (std::is_same_v<Args, coedge_t *> && ...))
    face_t *create_face(Args... args)
    {
        std::vector<coedge_t *> es = {args...};
        auto f = face_t::create(es);
        faces.insert(f);
        return f;
    }

    /**
     * @brief 多个顶点创建面
     *
     * @tparam Args
     */
    template <typename... Args>
        requires((N == 0 || sizeof...(Args) == N) && (std::is_same_v<Args, vertex_t *> && ...))
    face_t *create_face(Args... args)
    {
        std::vector<vertex_t *> vs = {args...};
        std::vector<coedge_t *> coes;
        for (std::size_t i = 0; i < vs.size(); ++i)
        {
            auto e = create_edge(vs[i], vs[(i + 1) % vs.size()]);
            coes.push_back(e);
        }

        auto f = face_t::create(coes);
        faces.insert(f);
        return f;
    }

    /**
     * @brief 删除顶点和相邻的面及其半边
     *
     * @param[in] v
     * @return true
     * @return false
     */
    bool remove(vertex_t *v)
    {
        if (v == nullptr)
            return false;

        // 先删除所有与 v 相关的边，注意这里要使用赋值而非引用，因为删除 e 会修改 v->edges，导致迭代器失效
        auto eList = v->edges;
        for (auto e : eList)
            remove(e);

        // 再删除 v
        vertices.erase(v);
        shape_t::remove(v);

        return true;
    }

    /**
     * @brief 删除边和相邻的面
     *
     * @param[in] e
     * @return true
     * @return false
     */
    bool remove(edge_t *e)
    {
        if (e == nullptr)
            return false;

        // 删除相邻的面
        auto co1 = e->coedge;
        auto co2 = e->coedge->twin;

        // loop 可能没有 face，不过没有关系
        if (co1->wire != nullptr)
            remove(co1->wire->face);
        if (co2->wire != nullptr)
            remove(co2->wire->face);

        coedges.erase(co1);
        coedges.erase(co2);
        edges.erase(e);

        shape_t::remove(e);
        return true;
    }

    /**
     * @brief 删除面（只删除面）
     *
     * @param[in] f
     * @return true
     * @return false
     */
    bool remove(face_t *f)
    {
        if (f == nullptr)
            return false;

        // 只需要移除所有 face_t 相关的属性
        faces.erase(f);
        shape_t::remove(f);

        return true;
    }

    /**
     * @brief 删除孤立顶点
     *
     * @return true
     * @return false
     */
    bool remove_isolated_vertex()
    {
        for (auto it = vertices.begin(); it != vertices.end();)
        {
            if ((*it)->edges.empty())
            {
                shape_t::remove(*it);
                it = vertices.erase(it);
            }
            else
                ++it;
        }
        return false;
    }

    /**
     * @brief  删除孤立边
     *
     * @return true
     * @return false
     */
    bool remove_isolated_edge()
    {
        for (auto it = edges.begin(); it != edges.end();)
        {
            if (shape_t::adjacent_edges(*it).empty())
            {
                shape_t::remove(*it);
                it = edges.erase(it);
            }
            else
                ++it;
        }
        return false;
    }

    /**
     * @brief  删除孤立面
     *
     * @return true
     * @return false
     */
    bool remove_isolated_face()
    {
        for (auto it = faces.begin(); it != faces.end();)
        {
            if (shape_t::adjacent_faces(*it).empty())
            {
                shape_t::remove(*it);
                it = faces.erase(it);
            }
            else
                ++it;
        }
        return false;
    }
};

} // namespace topo

} // namespace xy
